package ExecuteEngine;

import parse.*;
import java.util.*;

import Const.RC;
import SystemManagement.DataAttrInfo;
import SystemManagement.SM_Manager;

public class Select extends Operation{
	public Condition condition;
	public Operation op;
	public List<String> attr_list;
	public List<TableName> tb_list;
	public SM_Manager sm;
	public Tuple t;
	public List<String> titles;
	
	public Select(Condition con, Operation op){
		this.condition = con;
		this.op = op;
		this.type = Operation.SELECT;
	}
	
	public Select(List<TableName> tb_list, Operation op, SM_Manager sm){
		this.tb_list = tb_list;
		this.op = op;
		this.sm = sm;
		this.attr_list = new ArrayList<String>();
		this.condition = null;
	}
	
	public RC.rc Open(){
		if(this.condition == null)
		{
			List<List<DataAttrInfo>> attr_info = new ArrayList<List<DataAttrInfo>>();
			List<DataAttrInfo> info;
			boolean mark = false;
			
			for(int i=0; i<tb_list.size(); i++){
				info = new ArrayList<DataAttrInfo>();
				sm.GetDataAttrInfo(tb_list.get(i).GetTableName(), info);
				attr_info.add(info);
			}
			
			info = attr_info.get(0);
			for(int i=0; i<info.size(); i++){
				String attr = info.get(i).attrName;
				
				mark = false;
				for(int j=1; j<attr_info.size(); j++){
					for(int k=0; k<attr_info.get(j).size(); k++){
						if(attr.equals(attr_info.get(j).get(k).attrName) == false)
							continue;
						else{
							mark = true;
							break;
						}
					}
					
					if(!mark)
						break;
				}
				
				if(mark)
					attr_list.add(attr);
			}
		}
		
		RC.rc rc = op.Open();
		titles = op.GetTitles();
		return rc;
	}
	
	public boolean hasNext(){
		while(op.hasNext()){
			t = op.GetNext();
			
			if(condition != null){
				boolean bool = false;
				
				List<Boolean_term> term = condition.condition;
				for(int i=0 ;i<term.size(); i++){
					List<Boolean_factor> factor = term.get(i).term;
					
					boolean bool_term = true;	
					for(int j=0; j<factor.size(); j++){
						String attrName = factor.get(j).attrName;
												
						boolean bool_factor = false;
						
						if(factor.get(j).type == 1){
							Attribute ID1 = factor.get(j).ID1;
							Attribute ID2 = factor.get(j).ID2;
							String d1_s = null;
							String d2_s = null;
							int d1_n = 0;
							int d2_n = 0;
							
							int n = 0;
							for(int k=0; k<t.tuple.size(); k++){
								Element e = t.tuple.get(k);
								if(Tuple.Trim(ID1.GetRelName()).equals(Tuple.Trim(e.relName)) && Tuple.Trim(ID1.GetAttr_Name()).equals(Tuple.Trim(e.attrName))){
									if(e.value instanceof IntegerItem)
										d1_n = ((IntegerItem)e.value).value;
									else
										d1_s = ((VarcharItem)e.value).value.toString();
									
									n++;
								}
								else
								if(Tuple.Trim(ID2.GetRelName()).equals(Tuple.Trim(e.relName)) && Tuple.Trim(ID2.GetAttr_Name()).equals(Tuple.Trim(e.attrName))){
									if(e.value instanceof IntegerItem)
										d2_n = ((IntegerItem)e.value).value;
									else
										d2_s = ((VarcharItem)e.value).value.toString();
									
									n++;
								}
								
								if(n == 2)
									break;
							}
							
							if(d1_s != null){
								if(factor.get(j).Compare(d1_s, d2_s))
									bool_factor = true;
							}
							else{
								if(factor.get(j).Compare(d1_n, d2_n))
									bool_factor = true;
							}
						}
						else
						if(factor.get(j).subquery != null){
							Operation sub = factor.get(j).subquery;
							sub.Open();
							
							if(factor.get(j).all != null){
								bool_factor = true;
								
								while(sub.hasNext()){
									Tuple sub_tuple = sub.GetNext();
									Element e2 = sub_tuple.tuple.get(0);
									
									for(int n=0; n<t.tuple.size(); n++){
										Element e = t.tuple.get(n);

										if(e.attrName.equals(attrName)){
											if(e2.value instanceof IntegerItem){
												int n1 = ((IntegerItem)e.value).value;
												int n2 = ((IntegerItem)e2.value).value;
												if(!factor.get(j).Compare(n1, n2)){
													bool_factor = false;
													break;
												}
											}
											else{
												String s1 = ((VarcharItem)e.value).value.toString();
												String s2 = ((VarcharItem)e2.value).value.toString();
												if(!factor.get(j).Compare(s1, s2)){
													bool_factor = false;
													break;
												}
											}
										}
									}
									
									if(bool_factor == false)
										break;
								}
							}
							else
							if(factor.get(j).any != null){
								bool_factor = false;
								
								while(sub.hasNext()){
									Tuple sub_tuple = sub.GetNext();
									Element e2 = sub_tuple.tuple.get(0);
									
									for(int n=0; n<t.tuple.size(); n++){
										Element e = t.tuple.get(n);
										
										if(e.attrName.equals(attrName)){
											if(e2.value instanceof IntegerItem){
												int n1 = ((IntegerItem)e.value).value;
												int n2 = ((IntegerItem)e2.value).value;
												if(factor.get(j).Compare(n1, n2)){
													bool_factor = true;
													break;
												}
											}
											else{
												String s1 = ((VarcharItem)e.value).value.toString();
												String s2 = ((VarcharItem)e2.value).value.toString();
												if(factor.get(j).Compare(s1, s2)){
													bool_factor = true;
													break;
												}
											}
										}
										
										if(bool_factor)
											break;
									}
			
									if(bool_factor)
										break;
								}								
							}
							else{
								List<Element> subTuple = new ArrayList<Element>();
								bool_factor = false;
								
								while(sub.hasNext()){
									subTuple.add(sub.GetNext().tuple.get(0));
								}
								
								for(int n=0; n<t.tuple.size(); n++){
									Element e = t.tuple.get(n);
										
									if(e.attrName.equals(attrName)){
										for(int p=0; p<subTuple.size(); p++){
											Element e2 = subTuple.get(p);

											if(e2.value instanceof IntegerItem){
												int n1 = ((IntegerItem)e.value).value;
												int n2 = ((IntegerItem)e2.value).value;
												if(factor.get(j).Compare(n1, n2)){
													bool_factor = true;
													break;
												}
											}
											else{
												String s1 = ((VarcharItem)e.value).value.toString();
												String s2 = ((VarcharItem)e2.value).value.toString();
												if(factor.get(j).Compare(s1, s2)){
													bool_factor = true;
													break;
												}
											}
										}
											
										if(bool_factor)
											break;
									}
									
									if(bool_factor)
										break;
								}
							}
						}
						else{
							for(int k=0; k<t.tuple.size(); k++){
								Element e = t.tuple.get(k);
								
								if(attrName.equals(e.attrName)){
									if(e.value instanceof IntegerItem){
										if(factor.get(j).Compare(((IntegerItem)e.value).value))
											bool_factor = true;
									}
									else
									{
										StringBuffer s = new StringBuffer(factor.get(j).strValue);
										s.setLength(((VarcharItem)e.value).value.length());
										factor.get(j).strValue = s.toString();
										
										if(factor.get(j).Compare(((VarcharItem)e.value).value.toString()))
											bool_factor = true;
									}
									break;
								}
							}
						}
						
						if(bool_factor == false){
							bool_term = false;
							break;
						}		
					}
					
					if(bool_term){
						bool = true;
						break;
					}
				}
				
				if(bool)
					return true;
				else
					continue;
			}
			else{
				boolean mark = true;
				
				for(int i=0; i<attr_list.size(); i++){
					String attr = attr_list.get(i);
					
					boolean start = false;
					mark = true;
					String str_value = new String();
					int int_value = 0;
					
					for(int j=0; j<t.tuple.size(); j++){
						Element e = t.tuple.get(j);
						
						if(e.attrName.equals(attr)){
							if(!start){
								if(e.value instanceof VarcharItem)
									str_value = ((VarcharItem)(e.value)).value.toString();
								else
									int_value = ((IntegerItem)(e.value)).value;
								
								start = true;
							}
							else
							{
								if(e.value instanceof VarcharItem){
									if(!Tuple.Trim(str_value).equals(Tuple.Trim(((VarcharItem)(e.value)).value.toString()))){
										mark = false;
										break;
									}
								}
								else{
									if(int_value != ((IntegerItem)(e.value)).value){
										mark = false;
										break;
									}
								}
								
								t.tuple.remove(j);
							}
						}
					}
					
					if(!mark)
						break;
				}
				
				if(!mark)
					continue;
				else
					return true;
			}
		}
		return false;
	}
	
	public Tuple GetNext()
	{
		return this.t;
	}
	
	public void Close(){
		op.Close();
	}
	
	public List<String> GetTitles(){
		return titles;
	}
}
